# !/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2021/9/30 17:33
# @Author  : zuodengbo
# @Email   : zuodb@amoydx.com
# @File    : verify_code
# @Software: PyCharm
import asyncio
import random
from sanic.log import logger
from pymysql import DatabaseError

from utils.const import VerifyCodeStatus, DefaultConst
from utils.resp_code import *
from utils.common import time_now, active_time
from utils.redis_utils import sanic_redis

from user.models import VerifyCode

import string
import os

from captcha.image import ImageCaptcha, random_color


async def gen_verify_code(valid_time=1, mode="commons"):
    """
    随机生成6位的验证码
    :param: valid_time: 有效时间，单位分钟
    :return:
    """
    if mode == "sms":
        verify_code = "".join(random.sample([x for x in string.digits], 6))
    else:
        verify_code = "".join(random.sample([x for x in string.ascii_letters + string.digits], 6))
    valid_time = active_time(m=valid_time)
    try:
        # 将验证码存入数据库
        await VerifyCode.create(key=verify_code.lower(), code=verify_code, valid_time=valid_time)

        # 将验证码存入Redis缓存
        redis_pool = await sanic_redis.redis_pool()
        await redis_pool.set(key=verify_code.lower(), value=verify_code,
                             expire=DefaultConst.verify_code_expired_time)

        return RespCode.SUCCESS, verify_code
    except DatabaseError as e:
        msg = "Database error: {}".format(verify_code, e)
        logger.error(msg)
        return RespCode.DATABASE_ERROR, msg
    except Exception as e:
        msg = "Save verify code: {} failed: {}, line: {}".format(verify_code, e, e.__traceback__.tb_lineno)
        logger.error(msg)
        return RespCode.SAVE_VERIFY_CODE_FAILED, msg


async def verify_the_code(verify_code):
    """
    校验验证码
    :param verify_code: 
    :return: 
    """
    now = time_now("UTC")
    try:
        # 从Redis查找
        redis_pool = await sanic_redis.redis_pool()
        code = await redis_pool.get(verify_code.lower())
        if code:
            msg = "Check verify code from redis success !"
            logger.info(msg)
            await redis_pool.delete([verify_code.lower()])
            # sanic_redis.close()
            await VerifyCode.filter(key=verify_code.lower(), status=VerifyCodeStatus.unverified) \
                .update(status=VerifyCodeStatus.verified)
            return make_success_response(message=msg)
    except Exception as e:
        msg = "When query verify code from redis: {} something occurred: {} line: {}". \
            format(verify_code, e, e.__traceback__.tb_lineno)
        logger.warning(msg)

    try:
        # 从数据库查找
        code = await VerifyCode.filter(key=verify_code.lower(), status=VerifyCodeStatus.unverified).first()
        if not code:
            msg = "Verify code: {} is not exist or had been verified!".format(verify_code)
            logger.warning(msg)
            return make_error_response(code=RespCode.VERIFY_CODE_NOT_EXISTS, message=msg)
        # 确认是否在有效时间内
        valid_time = code.valid_time
        if valid_time < now:
            msg = "The verify code：{} expired".format(verify_code)
            logger.info(msg)
            return make_error_response(code=RespCode.VERIFY_CODE_EXPIRED, message=msg)
        else:
            code.status = VerifyCodeStatus.verified
            await code.save()
            msg = "Check verify code from database success !"
            logger.info(msg)
            return make_success_response(message=msg)
    except DatabaseError as e:
        msg = "Query verify code: {} failed: {} line: {}".\
            format(verify_code, e, e.__traceback__.tb_lineno)
        logger.error(msg)
        return make_error_response(code=RespCode.DATABASE_ERROR, message=msg)
    except Exception as e:
        msg = "When query verify code: {} other failure occurred: {} line: {}".\
            format(verify_code, e, e.__traceback__.tb_lineno)
        logger.error(msg)
        return make_error_response(code=RespCode.UNKNOWN_FAILURE, message=msg)


def generate_captcha(length=6):

    # 返回大小写字母
    letters = string.ascii_letters
    # 返回数字
    digits = string.digits

    # 随机选取 length 个字符
    verify_code = ''.join([random.choice(digits + letters) for j in range(length)])

    width, height = 85, 40

    # 创建图片生成器
    generator = ImageCaptcha(width=width, height=height)

    # 创建验证码图片
    img = generator.create_captcha_image(
        chars=verify_code, color=random_color(1, 255), background=random_color(1, 255))

    # 为图片增加干扰点
    generator.create_noise_dots(img, random_color(1, 255))
    # 为图片增加干扰线
    generator.create_noise_curve(img, random_color(1, 255))

    # 展示图片（展示图片的操作与上面保不保存无关）
    # img.show()

    # 保存生成的图片到本地
    file_dir = "save_img"
    if not os.path.exists(file_dir):
        os.mkdir(file_dir)
    file_name = "%s/%s.png" % (file_dir, "verify_code")
    img.save(file_name)

    return verify_code, img, file_name


if __name__ == "__main__":
    # s, ms, fn = generate_captcha()
    # print(s)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(gen_verify_code(mode="sms"))
    # print(verify_the_code())
